﻿using SharpCompress.Readers;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace UpgradeLoader
{
   public class Util
    {
        // 反序列化方法
        public static T DeserializeXml<T>(string filePath)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                using (StreamReader reader = new StreamReader(filePath))
                {
                    return (T)serializer.Deserialize(reader);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error during deserialization: " + ex.Message);
                return default;
            }
        }

       


        public static void SerializeXml(SoftwareUpdate obj,string filePath)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(obj.GetType());
                using (StreamWriter writer=new StreamWriter(filePath))
                {
                    serializer.Serialize(writer, obj);
                }
            }
            catch (Exception ex)
            {

                throw;
            }
        }

        public static T ToObj<T>(string filePath)
        {
            try
            {
                using (var reader = File.OpenRead(filePath))
                {
                    return (T)JsonSerializer.Deserialize<T>(reader);

                }
            }
            catch (Exception)
            {

                return default;
            }

        }
        public static string ToJson(object obj)
        {
            return JsonSerializer.Serialize(obj);
        }



        public static List<UpdateItem>GetUpdateList(string upitemDir)
        {
            if (!Directory.Exists(upitemDir)) return null;
            var list = new List<UpdateItem>();
            foreach (var fileName in Directory.EnumerateFiles(upitemDir))
            {
                var file = new FileInfo(fileName);
                UpdateItem item = new UpdateItem();
                item.Size = file.Length;
                item.FileName = file.Name;
                var n = file.Name.ToLower() ;
                item.Zip = n.EndsWith(".zip") || n.EndsWith(".7z") || n.EndsWith(".rar");
                item.MD5 = GetMD5HashFromFile(file.FullName);
                list.Add(item);
            }
            return list;
        }

        public static string GetMD5HashFromFile(string fileName)
        {
            using (var md5 = MD5.Create()) // 或者使用 new MD5CryptoServiceProvider()，但不推荐这样做。
            {
                using (var stream = File.OpenRead(fileName))
                {
                    var hash = md5.ComputeHash(stream);
                    return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
                }
            }
        }
        public static void DecompressZip(string zipFile, string extractFullDir)
        {
            using (FileStream originalFileStream = new FileStream(zipFile, FileMode.Open))
            {
                using (FileStream decompressedFileStream = new FileStream(extractFullDir, FileMode.Create))
                {
                    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(decompressedFileStream);
                    }
                }
            }
        }
        public static void UnzipFile(string zipFilePath, string destinationFolder)
        {

            if(!Directory.Exists(destinationFolder))
            {
                // 确保目标文件夹存在
                Directory.CreateDirectory(destinationFolder);
            }
            // 打开ZIP文件
            using (var zipToOpen = new FileStream(zipFilePath, FileMode.Open))
            {
                using (var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Read))
                {
                    foreach (var entry in archive.Entries)
                    {
                        // 解压每个ZIP条目
                        if (entry.Length == 0) continue; // 忽略空条目

                        // 定义目标文件路径
                        var destFileName = Path.Combine(destinationFolder, entry.FullName);

                        // 确保文件夹路径存在
                        var destinationDirectory = Path.GetDirectoryName(destFileName);

                        if(!Directory.Exists(destinationDirectory))
                        {
                            Directory.CreateDirectory(destinationDirectory!);
                        }
                        // 将文件内容复制到目标路径
                        using (var entryStream = entry.Open())
                        using (var fileStream = new FileStream(destFileName, FileMode.Create))
                        {
                            entryStream.CopyTo(fileStream);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 解压文件
        /// </summary>
        /// <param name="zipPath">压缩文件路径</param>
        /// <param name="dirPath">解压到文件夹路径</param>
        /// <param name="password">密码</param>
        public static void DeCompressionFile(string zipPath, string dirPath, string password = "")
        {
            if (!File.Exists(zipPath))
            {
                throw new ArgumentNullException("zipPath压缩文件不存在");
            }
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            try
            {
                using (Stream stream = File.OpenRead(zipPath))
                {
                    var option = new ReaderOptions()
                    {
                        ArchiveEncoding = new SharpCompress.Common.ArchiveEncoding()
                        {
                            Default = Encoding.UTF8
                        }
                    };
                    if (!string.IsNullOrWhiteSpace(password))
                    {
                        option.Password = password;
                    }

                    var reader = ReaderFactory.Open(stream, option);
                    while (reader.MoveToNextEntry())
                    {
                        if (reader.Entry.IsDirectory)
                        {
                            Directory.CreateDirectory(Path.Combine(dirPath, reader.Entry.Key));
                        }
                        else
                        {
                            //创建父级目录，防止Entry文件,解压时由于目录不存在报异常
                            var file = Path.Combine(dirPath, reader.Entry.Key);
                            Directory.CreateDirectory(Path.GetDirectoryName(file));
                            reader.WriteEntryToFile(file);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #region 文件夹操作

        /// <summary>
        /// 复制文件夹及文件 不含根目录
        /// </summary>
        /// <param name="sourceFolder">原文件路径</param>
        /// <param name="destFolder">目标文件路径</param>
        public static void CopyChildFolderFile(string sourceFolder, string destFolder, bool overwrite, params string[] exceptFolders)
        {
            try
            {
                if (!Directory.Exists(sourceFolder)) return;
                CreateFolder(destFolder);
                //得到原文件根目录下的所有文件
                string[] files = Directory.GetFiles(sourceFolder);
                foreach (string file in files)
                {
                    string name = Path.GetFileName(file);
                    string dest = Path.Combine(destFolder, name);
                    File.Copy(file, dest, overwrite);//复制文件
                }
                //得到原文件根目录下的所有文件夹
                string[] folders = Directory.GetDirectories(sourceFolder);
                foreach (string folder in folders)
                {
                    string name = Path.GetFileName(folder);
                    //if (string.Compare(name, "logs", true) == 0 || string.Compare(name, "log", true) == 0) continue;//过滤日志
                    if (exceptFolders != null && exceptFolders.Any(fname => string.Compare(name, fname, true) == 0)) continue;
                    string dest = Path.Combine(destFolder, name);
                    CopyChildFolderFile(folder, dest, overwrite, exceptFolders);//构建目标路径,递归复制文件
                }
            }
            catch (Exception ex)
            {
                throw ex;
               // WriteRed($"[{nameof(CopyChildFolderFile)}]{ex.Message}", ex);
            }
        }



        public static void CreateFolder(string folderPath)
        {
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
        }
        #endregion

        #region 文件下载

       public static  async Task DownloadFileAsync(string url, string localPath)
        {
            using (HttpClient client = new HttpClient())
            {
                using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        return;
                    }
                    using (Stream stream = await response.Content.ReadAsStreamAsync())
                    {
                        using (FileStream fileStream = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
                        {
                            byte[] buffer = new byte[8192];
                            int bytesRead;
                            long totalBytesRead = 0;
                            long totalBytes = response.Content.Headers.ContentLength ?? -1;

                            while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                            {
                                await fileStream.WriteAsync(buffer, 0, bytesRead);
                                totalBytesRead += bytesRead;
                                // 处理下载进度，例如更新UI
                                Console.WriteLine($"下载进度：{totalBytesRead}/{totalBytes}");
                            }
                        }
                    }
                }
            }
        }

        internal static void DownloadFileAsync(string server, UpdateItem item, string localDir)
        {
            throw new NotImplementedException();
        }
        #endregion

    }
}
